package com.hulk.rpc.config.client;

import com.hulk.rpc.annotation.HulkService;
import com.hulk.rpc.config.common.ConfigException;
import com.hulk.rpc.config.common.HostPort;
import com.hulk.rpc.discover.Discover;
import com.hulk.rpc.discover.Discover.DiscoverEnum;
import com.hulk.rpc.loadbalance.LoadBalance;
import com.hulk.rpc.loadbalance.LoadBalance.LoadBalanceEnum;
import com.hulk.rpc.serialize.Serializer;
import com.hulk.rpc.serialize.Serializer.SerializeEnum;
import com.typesafe.config.Config;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.hulk.rpc.config.common.ConfigUtils.getIntOrElse;
import static com.hulk.rpc.config.common.ConfigUtils.getStringOrElse;

/**
 * 客户端连接远程服务配置
 *
 * @author xuxukang
 * @date 2019-03-24 10:50
 */
@Data
@Accessors(chain = true)
public class AppConfig {

  // 1.直连（app的多个节点地址）2.非直连（注册中心服务的地址，如zookeeper）
  // private List<HostPort> hostPortList;
  private String group = HulkService.default_group;
  private String app = HulkService.default_app;
  private Serializer serializer = SerializeEnum.proto.getSerializer();
  //future
  private int globalTimeOut = 0;
  //客户端限流
  private int maxRequestWait = 0;
  private int serverErrorThreshold = 16;
  private int connectorPerServer = 1;
  private int connectErrorThreshold = 2 * serverErrorThreshold / connectorPerServer;
  // 用于发现服务
  private Discover discover;
  //初始化app连接时的默认负载均衡器，可以为空
  private LoadBalance loadBalance = LoadBalanceEnum.round_robin.getLoadBalance();

  public static List<AppConfig> parse(List<? extends Config> configs) {
    return configs.stream().map(config -> {
      try {
        return parse(config);
      } catch (Exception e) {
        throw new ConfigException(e);
      }
    }).collect(Collectors.toList());
  }

  /**
   * 创建客户端依赖的app配置
   *
   * @param config 配置文件
   * @return 客户端代理类用于调用的app对象
   */
  @SuppressWarnings({"rawtypes"})
  private static AppConfig parse(Config config) {
    Objects.requireNonNull(config);
    String group = getStringOrElse(config, "group", HulkService.default_group);
    String app = getStringOrElse(config, "app", HulkService.default_app);
    int globalTimeOut = getIntOrElse(config, "globalTimeOut", 0);
    int maxRequestWait = getIntOrElse(config, "maxRequestWait", 10000);
    int connectorPerServer = getIntOrElse(config, "connectorPerServer", 1);
    int serverErrorThreshold = getIntOrElse(config, "serverErrorThreshold", 16);
    int connectErrorThreshold = getIntOrElse(config, "connectErrorThreshold",
            2 * serverErrorThreshold / connectorPerServer);

    String serializerName = getStringOrElse(config, "serializer", SerializeEnum.proto.name());
    Serializer serializer = SerializeEnum.valueOf(serializerName).getSerializer();

    String discoverName = getStringOrElse(config, "discover", DiscoverEnum.direct.name());
    Discover discover = DiscoverEnum.valueOf(discoverName).getDiscover();
    List<String> hostPortStrings = config.getStringList("hostPorts");
    List<HostPort> hostPorts = hostPortStrings.stream().map(HostPort::new)
            .collect(Collectors.toList());
    discover.init(hostPorts);

    String loadBalanceName = getStringOrElse(config, "loadBalance", LoadBalanceEnum.round_robin.name());
    LoadBalance loadBalance = LoadBalanceEnum.valueOf(loadBalanceName).getLoadBalance();

    AppConfig appConfig = new AppConfig().setApp(app).setGroup(group)
            .setGlobalTimeOut(globalTimeOut).setMaxRequestWait(maxRequestWait)
            .setConnectorPerServer(connectorPerServer).setServerErrorThreshold(serverErrorThreshold)
            .setConnectErrorThreshold(connectErrorThreshold).setSerializer(serializer)
            .setDiscover(discover).setLoadBalance(loadBalance);

    return appConfig;
  }

}
